package com.example.seakdreamandroid.sleepRecord;


import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CalendarView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.example.seakdreamandroid.Constant;
import com.example.seakdreamandroid.R;
import com.example.seakdreamandroid.accountInfo.PopupAndDarkenWindow;
import com.example.seakdreamandroid.entity.User;
import com.example.seakdreamandroid.sleep.entity.SleepInfo;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.formatter.ValueFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class RecordPerWeek extends Fragment {
    private BarChart barChart;
    private static final int LAYOUT_ID = R.layout.fragment_rpw;
    private static final String TAG = "RecordPerWeek";
    private static final int OK = 1;
    private static final int ERROR = 2;
    private View v;
    private Activity activity;
    private LimitLine avgLine;
    private List<BarEntry> barData;
    private int[] weekData = new int[7];
    private List<SleepInfo> records;
    private ImageView left;
    private ImageView right;
    private LinearLayout datePicker;
    private TextView firstOfWeek;
    private TextView endOfWeek;
    private TextView date;
    private TextView sleepTimeHour;
    private TextView sleepTimeMinute;
    private TextView avgSleepTimeHour;
    private TextView avgSleepTimeMinute;
    private PopupAndDarkenWindow datePickerPopup;
    private Calendar monday;
    private SimpleDateFormat dateFormat = new SimpleDateFormat("MM月dd日");
    private SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private User user;
    private Handler handler;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        activity = getActivity();
        v = inflater.inflate(LAYOUT_ID,container);
        findView();
        initDatePickerPopup();
        initBarChart();
        initOther();
        setListener();
        getData();
        return v;
    }

    private void initOther() {
        records = new ArrayList<SleepInfo>();
        user = (User) activity.getApplicationContext();
        monday = Calendar.getInstance();
        monday.setTimeInMillis(System.currentTimeMillis());
        if(monday.get(Calendar.DAY_OF_WEEK) == 1){
            monday.set(Calendar.DAY_OF_MONTH,monday.get(Calendar.DAY_OF_MONTH)-6);
        }else{
            monday.set(Calendar.DAY_OF_MONTH,monday.get(Calendar.DAY_OF_MONTH)+2-monday.get(Calendar.DAY_OF_WEEK));
        }
        monday.set(Calendar.HOUR_OF_DAY,0);
        monday.set(Calendar.MINUTE,0);
        monday.set(Calendar.SECOND,0);
        handler = new Handler(activity.getMainLooper()){
            @Override
            public void handleMessage(@NonNull Message msg) {
                switch(msg.what){
                    case OK:
                        changeBarChartData();
                        break;
                    case ERROR:
                        Toast.makeText(activity, "网络故障，获取数据失败", Toast.LENGTH_SHORT).show();
                        break;
                }
            }
        };
        setRange();
    }

    private void setRange() {
        Date temp = this.monday.getTime();
        firstOfWeek.setText(dateFormat.format(temp));
        temp.setDate(temp.getDate()+6);
        endOfWeek.setText(dateFormat.format(temp));
        noSleepTime();
        date.setVisibility(View.INVISIBLE);
    }

    private void initDatePickerPopup() {
        datePickerPopup = new PopupAndDarkenWindow(activity, R.layout.popup_date_picker);
        datePickerPopup.init();
        datePickerPopup.setPopupViewListener(new PopupAndDarkenWindow.SetPopupViewListenerCallBack() {
            @Override
            public void setListener(View v, PopupAndDarkenWindow popupAndDarkenWindow) {
                PopupWindow popupWindow = popupAndDarkenWindow.getPopupWindow();
                CalendarView calendarView = v.findViewById(R.id.calendar);
                calendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
                    @Override
                    public void onSelectedDayChange(@NonNull CalendarView view, int year, int month, int dayOfMonth) {
                        popupWindow.dismiss();
                        noSleepTime();
                        date.setVisibility(View.INVISIBLE);
                        monday.set(year,month,dayOfMonth);
                        monday.set(Calendar.DAY_OF_MONTH,monday.get(Calendar.DAY_OF_MONTH) + 2 - monday.get(Calendar.DAY_OF_WEEK));
                        setRange();
                        getData();
                    }
                });
            }
        });
    }

    private void noSleepTime(){
        sleepTimeMinute.setText("--");
        sleepTimeHour.setText("--");
    }
    private void noAvgSleepTime(){
        avgSleepTimeMinute.setText("--");
        avgSleepTimeHour.setText("--");
    }
    private void setSleepTimeHour(int hour,int minute){
        sleepTimeHour.setText(hour+"");
        sleepTimeMinute.setText(minute+"");
    }
    private void setAvgSleepTimeHour(int hour,int minute){
        avgSleepTimeHour.setText(hour+"");
        avgSleepTimeMinute.setText(minute+"");
    }


    private void setListener() {
        left.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                monday.set(Calendar.DAY_OF_MONTH,monday.get(Calendar.DAY_OF_MONTH)-7);
                setRange();
                getData();
            }
        });
        right.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                monday.set(Calendar.DAY_OF_MONTH,monday.get(Calendar.DAY_OF_MONTH)+7);
                setRange();
                getData();
            }
        });
        datePicker.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                datePickerPopup.popupWindow();
            }
        });
        barChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
            @Override
            public void onValueSelected(Entry e, Highlight h) {
                date.setVisibility(View.VISIBLE);
                Date temp = monday.getTime();
                temp.setDate(temp.getDate()+(int)e.getX() - 1);
                date.setText(dateFormat.format(temp));
                int minute = weekData[(int)e.getX()-1]/60;
                setSleepTimeHour(minute/60,minute%60);
            }

            @Override
            public void onNothingSelected() {
                noSleepTime();
                date.setVisibility(View.INVISIBLE);
            }
        });

    }

    private void changeBarChartData() {
        BarDataSet dataSet = new BarDataSet(barData,"睡眠时长");
        dataSet.setColor(getResources().getColor(R.color.purple_200));
        BarData data = new BarData(dataSet);
        data.setDrawValues(false);
        data.setBarWidth(0.3f);
        barChart.setData(data);
        setAvgLine();
        setAvgSleepTimeHour();
        barChart.invalidate();
    }

    private void setAvgSleepTimeHour() {
        if(barData.size() == 0){
            noAvgSleepTime();
            return;
        }
        int secondSum = 0;
        for(int second:weekData){
            secondSum+=second;
        }
        Log.i(TAG,secondSum+"");
        int minuteSum = secondSum/60;
        int avgMinute = minuteSum/barData.size();
        setAvgSleepTimeHour(avgMinute/60,avgMinute%60);
    }

    private void getData(){
        records.clear();
        OkHttpClient client = new OkHttpClient();
        Date right = monday.getTime();
        right.setDate(right.getDate()+7);
        Log.i(TAG,"monday = " + timeFormat.format(monday.getTime()));
        Log.i(TAG,"right = " + timeFormat.format(right));
        Request request = new Request.Builder()
                .url(Constant.BASE_URL + "sleep/findSleepInfoInRange?userId=" + user.getUserId() + "&left=" + timeFormat.format(monday.getTime()) + "&right=" + timeFormat.format(right))
                .get()
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                Log.e(TAG,"onFailure, getData");
                e.printStackTrace();
                Message msg = handler.obtainMessage();
                msg.what=ERROR;
                handler.sendMessage(msg);

            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                String result = response.body().string();
                try{
                    JSONObject obj = new JSONObject(result);
                    if(obj.getString("data").equals("null")) {
                        return;
                    }
                    JSONArray array = obj.getJSONArray("data");
                    for(int i = 0; i < array.length(); i++){
                        JSONObject temp = array.getJSONObject(i);
                        SleepInfo sleepInfo = new SleepInfo();
                        sleepInfo.setSleepId(temp.getString("sleepId"));
                        sleepInfo.setUserId(temp.getString("userId"));
                        sleepInfo.setAsleepTime(temp.getString("asleepTime"));
                        sleepInfo.setAwakeTime(temp.getString("awakeTime"));
                        records.add(sleepInfo);
                    }

                } catch (JSONException e) {
                    e.printStackTrace();
                }finally {
                    generateWeekData();
                    Message msg = handler.obtainMessage();
                    msg.what = OK;
                    handler.sendMessage(msg);
                }
            }
        });
    }

    private void generateWeekData() {
        for(int i = 0; i < 7; i++){
            weekData[i] = 0;
            Calendar temp = Calendar.getInstance();
            temp.set(monday.get(Calendar.YEAR),monday.get(Calendar.MONTH),monday.get(Calendar.DAY_OF_MONTH)+i,0,0,0);
            long limitLeft = temp.getTimeInMillis();
            Log.i("limitLeft",temp.get(Calendar.DAY_OF_MONTH)+"");
            temp.set(Calendar.DAY_OF_MONTH,temp.get(Calendar.DAY_OF_MONTH)+1);
            long limitRight = temp.getTimeInMillis();
            Log.i("limitRight",temp.get(Calendar.DAY_OF_MONTH)+"");
            for(SleepInfo record:records){
                Log.i("startTime",record.getAsleepTime());
                Log.i("endTime",record.getAwakeTime());
                long startTime = record.getAsleepTimeInMill();
                long endTime = record.getAwakeTimeInMill();
                if(startTime>limitRight)break;
                if(startTime>limitLeft && endTime<limitRight){
                    weekData[i] += (endTime-startTime)/SleepInfo.SECOND_MILL;
                }else if(startTime<limitLeft && endTime > limitRight){
                    weekData[i] += SleepInfo.DAY_MILL/SleepInfo.SECOND_MILL;
                    break;
                }else if(startTime<limitLeft && endTime <limitRight && endTime>limitLeft){
                    weekData[i] += (endTime-limitLeft)/SleepInfo.SECOND_MILL;
                }else if(startTime > limitLeft && startTime < limitRight && endTime > limitRight){
                    weekData[i] += (limitRight-startTime)/SleepInfo.SECOND_MILL;
                    break;
                }
                Log.i("h",weekData[i]+"");
            }
        }
        for(int i = 0; i < 7; i++){
            Log.i(TAG+i,weekData[i]+"");
        }
        generateBarData();
    }

    private void generateBarData() {
        List<BarEntry> barData = new ArrayList<BarEntry>();
        for(int i = 0; i<7;i++){
            if(weekData[i] == 0)continue;
            barData.add(new BarEntry(i+1,weekData[i]));
        }
        this.barData = barData;
    }

    private float getDataAvg(){
        if(barData.size() == 0){
            return 0;
        }
        float sum = 0;
        for(BarEntry entry:barData){
            sum += entry.getY();
        }
        return sum/barData.size();
    }

    private void setAvgLine() {
        if(avgLine != null){
            barChart.getAxisLeft().removeAllLimitLines();
        }
        avgLine = new LimitLine(getDataAvg(),"睡眠时间平均线");
        barChart.getAxisLeft().addLimitLine(avgLine);
    }

    private void findView() {
        barChart = v.findViewById(R.id.bar_chart);
        left = v.findViewById(R.id.left);
        right = v.findViewById(R.id.right);
        datePicker = v.findViewById(R.id.date_picker);
        firstOfWeek = v.findViewById(R.id.first_of_week);
        endOfWeek = v.findViewById(R.id.end_fo_week);
        date = v.findViewById(R.id.date);
        sleepTimeHour = v.findViewById(R.id.sleep_time_hour);
        sleepTimeMinute = v.findViewById(R.id.sleep_time_minute);
        avgSleepTimeHour = v.findViewById(R.id.avg_sleep_time_hour);
        avgSleepTimeMinute = v.findViewById(R.id.avg_sleep_time_minute);
    }

    private void initBarChart() {
        barChart.setDescription(null);
        barChart.setScaleEnabled(false);
        XAxis xAxis = barChart.getXAxis();
        YAxis leftYAxis = barChart.getAxisLeft();
        YAxis rightYAxis = barChart.getAxisRight();
        xAxis.setDrawGridLines(false);
        leftYAxis.setDrawGridLines(false);
        rightYAxis.setDrawGridLines(false);
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setValueFormatter(new ValueFormatter() {
            private String[] dayOfWeek = {"星期一","星期二","星期三","星期四","星期五","星期六","星期天"};

            @Override
            public String getAxisLabel(float value, AxisBase axis) {
                return dayOfWeek[(int)value - 1];
            }
        });
        rightYAxis.setDrawAxisLine(false);
        rightYAxis.setDrawLabels(false);
        leftYAxis.setDrawLabels(false);
        leftYAxis.setDrawAxisLine(false);
        leftYAxis.setAxisMinimum(0);
        xAxis.setAxisMinimum(0.5f);
        xAxis.setAxisMaximum(7.5f);
        barChart.animateY(500);

    }
}
